package com.suray.wcs.service.thread;


import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.path.enums.DirectionStatus;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.res.enums.PalletStatus;
import com.suray.wcs.res.enums.RgvStatus;
import com.suray.wcs.res.msgparse.ByteBeanUtil;
import com.suray.wcs.res.msgparse.HeartBaseResult;
import com.suray.wcs.res.msgparse.MapDataResult;
import com.suray.wcs.res.msgparse.ResultBase;
import com.suray.wcs.service.core.util.LockNodeManager;
import com.suray.wcs.service.core.util.LongConnSendUtilLora;
import com.suray.wcs.service.enums.ElectricStatus;
import com.suray.wcs.res.enums.RgvType;
import com.suray.wcs.service.init.SystemInit;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.pojo.Rgv60;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.base.RgvBaseMessage;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.message.RgvLifeRecMessage;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.message.RgvLifeSendMessage;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.util.RgvCargoStatus;
import com.suray.wcs.service.rescontact.ResultContainer;
import com.suray.wcs.service.rescontact.ToRes;
import com.suray.wcs.service.system.service.impl.CodeDBServiceImpl;
import com.suray.wcs.service.system.service.impl.WareHouseDBServiceImpl;
import com.suray.wcs.service.system.service.impl.RgvDBServiceImpl;
import com.suray.wcs.service.util.WcsUtil;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * @author Shaozn
 */
public class WcsHeartThread extends Thread {
    private static final CodeDBServiceImpl codeDBService = SpringContextHolder.getBean(CodeDBServiceImpl.class);
    private static WareHouseDBServiceImpl wareHouseDBService = SpringContextHolder.getBean(WareHouseDBServiceImpl.class);


    private Rgv rgv;
    /**
     * 心跳间隔时间
     */
    private static final int INTERVAL_TIME = 800;
    private static Logger log = LoggerFactory.getLogger(WcsHeartThread.class);
    private static final RgvDBServiceImpl rgvdbService = SpringContextHolder.getBean(RgvDBServiceImpl.class);
    private boolean syncTiming = false;
    private static Integer disconnectionTimes = 0;
    private static Integer lockTime = 0;

    /**
     * 构造方法
     */
    public WcsHeartThread(Rgv rgv) {
        super(rgv.getRgvDB().getRgvNo() + "号车心跳线程");
        this.rgv = rgv;
    }

    @SneakyThrows
    @Override
    public void run() {
        while (true) {
            try {
                if (RgvType.FOUR_GENERATIONS.getValue().equals(rgv.getRgvDB().getRgvType())) {
                    doExec(ToRes.getInstance(rgv).heartRequest(ByteBeanUtil.toByte(rgv.getRgvHeart(), rgv.getRgvDB().getRgvNo())));
                } else if (rgv.checkRgvType(RgvType.FIVE_POINT_FOUR_TL) && !rgv.isStopHeart()) {
                    RgvBaseMessage rgvBaseMessage = ToRes.getInstance(rgv).heartRequest(new RgvLifeSendMessage(rgv));
                    if (!syncTiming && rgv.getCurResTaskNo() == null) {
                        if (rgvBaseMessage != null) {
                            if (rgvBaseMessage instanceof RgvLifeRecMessage) {
                                syncTime((RgvLifeRecMessage) rgvBaseMessage, rgv);
                            } else {
                                LoggerUtil.error("数据返回类型错误-->" + rgvBaseMessage, this.getClass());
                            }
                        }
                    }
                } if (rgv.checkRgvType(RgvType.RGV_SEER_COMM)) {
                    ((Rgv60) rgv).analyzeData();
                }
            } catch (IOException e) {
                disconnectionTimes++;
                if (RgvType.FOUR_GENERATIONS.getValue().equals(rgv.getRgvDB().getRgvType())) {
                    if (disconnectionTimes % 8 == 0) {
                        ++lockTime;
                        if (lockTime < 100) {
                            LockNodeManager.updateLockedNodeUnLockTimeIncrement(rgv, 10000);
                        } else {
                            LockNodeManager.updateLockedNodeUnLockTimeIncrement(rgv, Integer.MAX_VALUE);
                        }
                    }
                } else if (rgv.checkRgvType(RgvType.FIVE_POINT_FOUR_TL) && !rgv.isStopHeart()) {
                    if (disconnectionTimes % 2 == 0) {
                        ++lockTime;
                        if (lockTime < 100) {
                            LockNodeManager.updateLockedNodeUnLockTimeIncrement(rgv, 10000);
                        } else {
                            LockNodeManager.updateLockedNodeUnLockTimeIncrement(rgv, Integer.MAX_VALUE);
                        }
                    }
                }
                LongConnSendUtilLora.socketMap.remove(rgv);
                // 小车不是故障状态才设置离线
                if (rgv.getRgvStatus() != RgvStatus.ERROR) {
                    rgv.setRgvStatus(RgvStatus.OFF_LINE);
                    rgv.offLinePing();
                } else {
                    rgv.setStatusDescription("小车离线");
                }
                log.warn(rgv.getRgvName() + "心跳通讯异常", e.getMessage());
                Thread.sleep(3000);
            } catch (Exception e) {
                log.error("心跳通讯出现故障", e);
                log.warn(rgv.getRgvName() + "心跳通讯异常", e.getMessage());
                Thread.sleep(5000);
            }
            try {
                Thread.sleep(INTERVAL_TIME);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void syncTime(RgvLifeRecMessage rgvLifeRecMessage, Rgv rgv) {
        if (!rgvLifeRecMessage.isTimeSync()) {
            syncTiming = true;
            new Thread(() -> {
                try {
                    ToRes toRes = ToRes.getInstance(rgv);
                    toRes.syncTime(0);
                } catch (Exception e) {
                    WcsUtil.exceptionLog(e, this.getClass());
                }
                syncTiming = false;
            }).start();
        }
    }

    /**
     * 执行结果
     *
     * @param receiveByte
     */
    public static void doExec(byte[] receiveByte) {
        long receiveTime = System.currentTimeMillis();
        ResultBase receiveMsg = ByteBeanUtil.parseByte(receiveByte);
        receiveMsg.setRetTime(receiveTime);
        if (receiveMsg instanceof HeartBaseResult) {
            Rgv rgv = SystemInit.getByRgvNo(receiveMsg.getDeviceNo());
            baseInfoHandle((HeartBaseResult) receiveMsg, rgv);
        } else if (receiveMsg instanceof MapDataResult) {
            Rgv rgv = SystemInit.getByRgvNo(receiveMsg.getDeviceNo());
            mapInfoHandle((MapDataResult) receiveMsg, rgv);
        }
    }

    /**
     * 地图模式下发结果处理
     */
    private static void mapInfoHandle(MapDataResult mapDataResult, Rgv rgv) {
        ResultContainer.getContainer(rgv).putMapResultMap(mapDataResult.getDeviceNo(), mapDataResult);
    }

    /**
     * 基本信息模式返回结果处理
     */
    private static void baseInfoHandle(HeartBaseResult heartBaseResult, Rgv rgv) {
        if (RgvStatus.parseStatus(heartBaseResult.getRgvStatus()) != RgvStatus.OFF_LINE) {
            ResultContainer.getContainer(rgv).putResult(heartBaseResult.getCmdNo(), heartBaseResult);
            ResultContainer.getContainer(rgv).putResult(heartBaseResult.getTaskNo(), heartBaseResult);
            rgv.setPalletStatus(PalletStatus.parseStatus(heartBaseResult.getPalletStatus()));
            rgv.setDirection(parseDirection(heartBaseResult.getDriveDirection(), SystemInit.wareHouseDB == null ? 1 : SystemInit.wareHouseDB.getMapDirection()));
            rgv.setElectricStatus(ElectricStatus.parseStatus(heartBaseResult.getBattery(), rgv));
            rgv.setResTaskResult(heartBaseResult.getTaskResult());
            rgv.setBattery(heartBaseResult.getBattery());
            rgv.setSameMapVersion(heartBaseResult.getIsSameMapVersion() == 0 ? true : false);
            rgv.setCurrSegment(heartBaseResult.getCurentSegment());
            rgv.setSegmentLocation(heartBaseResult.getSegmentLocation());
            // 如果当前不存在故障则显示 告警信息
//            if (rgv.getRgvStatus() != RgvStatus.ERROR) {
//                rgv.setErrorMessage(codeDBService.getCodeDescByWarning(heartBaseResult.getStatusMessage()));
//            }
            String codeDescByWarning = codeDBService.getCodeDescByWarning(heartBaseResult.getStatusMessage());
            if (codeDescByWarning != null) {
                rgv.setStatusDescription(codeDescByWarning);
            } else if (rgv.getCurResTaskNo() == null) {
                rgv.setStatusDescription(null);
            }
            rgv.setBarrierAtOne(heartBaseResult.getBarrierAtOne());
            rgv.setBarrierAtTwo(heartBaseResult.getBarrierAtTwo());
            rgv.setBarrierAtThree(heartBaseResult.getBarrierAtThree());
            rgv.setBarrierAtFour(heartBaseResult.getBarrierAtFour());
            rgv.setHasPallet(RgvCargoStatus.INVALID);
            rgv.setLocationCode(String.valueOf(heartBaseResult.getOffsetGroundCode()));
            if (heartBaseResult.getCurBarcode() != 0xffff1f) {
                rgv.setGroundCode(String.format("%06d", heartBaseResult.getCurBarcode()));
            } else {
                rgv.setGroundCode(null);
            }
            rgv.setDirectionStatus(DirectionStatus.parseStatus(heartBaseResult.getReserveStatus()));
            //与RES约定当坐标为(255,255,31)时视为无坐标
            if (heartBaseResult.getX() == 255 || heartBaseResult.getY() == 255 || heartBaseResult.getZ() == 31) {
                rgv.setCurLocation(null);
            } else {
                rgv.setCurLocation(new Node(heartBaseResult.getX(), heartBaseResult.getY(), heartBaseResult.getZ()));
                if (rgv.getRgvDB().getLocationNode() == null || !rgv.getRgvDB().getLocationNode().equals(rgv.getCurLocation())) {
                    rgv.getRgvDB().setLocation(rgv.getCurLocation().toString());
                    rgvdbService.updateRgvLocation(rgv.getRgvDB());
                    LockNodeManager.updateLocationLock(rgv);
                }
            }
            rgv.updateWcsTimeModuleResultBO(rgv.getCurLocation());
        }
        rgv.setRgvResStatus(RgvStatus.parseStatus(heartBaseResult.getRgvStatus()));
        //心跳结果中的状态不可消除WCS中的故障状态，必须人工消除
        if (rgv.getRgvStatus() != RgvStatus.ERROR) {
            rgv.setRgvStatus(RgvStatus.parseStatus(heartBaseResult.getRgvStatus()));
        }
    }

    private static Integer parseDirection(Integer resDirection, Integer carDirection) {
        if (resDirection == 0) {
            return resDirection;
        }
        if (resDirection < 0 || resDirection > 4) {
            return 5;
        }
        switch (carDirection) {
            case 3:
                return (resDirection + 0) % 4;
            case 2:
                return (resDirection + 1) % 4;
            case 1:
                return (resDirection + 2) % 4;
            case 4:
                return (resDirection + 3) % 4;
        }
        return 5;
    }
}
